#ifndef N1DELEGATE_H_2006_11_19
#define N1DELEGATE_H_2006_11_19

/******************************************************

Usage:

class Delegate {
public:
    void delegate1() {};
    int delegate2(double f) {};
};

class Caller {
    N1DelegatePtr<void> *m_p1;
    N1DelegatePtr<int, double> *m_p2;
    N1DelegatePtr<int, double> *m_p3;

public:
    void call()
    {
        m_p1->invoke();
        m_p2->invoke(3.1415);
    }

    setDelegate1(N1DelegatePtr<void>* p);
    setDelegate2(N1DelegatePtr<int, double>* p);

    template<class Handler>
    void setDelegate3(Handler &obj, int (Handler::*Func)(double))
    {
        m_p3 = new N1Delegate<Handler,int, double>(&obj, Func);
    };
};

Caller    c;
Delegate  d;

c.setDelegate1(new N1Delegate<Delegate,void>(&d, &Deleate::delegate1));
c.setDelegate2(new N1Delegate<Delegate,int, double>(&d, &Deleate::delegate2));
c.setDelegate3(d, &Deleate::delegate2);
******************************************************/

template<typename Ret, typename T1=void, typename T2=void>
class N1DelegatePtr 
{
public:
    virtual ~N1DelegatePtr() { };
    virtual Ret invoke(T1 p1, T2 p2)=0;
};

template<typename Ret, typename T1>
class N1DelegatePtr<Ret, T1, void> {
public:
    virtual ~N1DelegatePtr() { };
    virtual Ret invoke(T1 p1)=0;
};

template<typename Ret>
class N1DelegatePtr<Ret, void, void> {
public:
    virtual ~N1DelegatePtr() { };
    virtual Ret invoke()=0;
};

template<>
class N1DelegatePtr<void, void, void> {
public:
    virtual ~N1DelegatePtr() { };
    virtual void invoke()=0;
};

/*****************************************************/

template<class T, typename Ret=void, 
         typename T1=void, typename T2=void> 
class N1Delegate : public N1DelegatePtr<Ret,T1,T2>
{ 
    T *m_ptr;
public:
    typedef Ret (T::*TFunction)(T1, T2);
protected:
    TFunction m_function;

    N1Delegate(const N1Delegate &d) { };
public: 

    N1Delegate(T* ptr, TFunction function) 
        : m_ptr(ptr), m_function(function) 
    { };

    virtual Ret invoke(T1 p1, T2 p2)
    {
        return (m_ptr->*m_function)(p1, p2);
    };
};

template<class T, typename Ret, 
         typename T1> 
class N1Delegate<T, Ret, T1, void> : public N1DelegatePtr<Ret,T1,void>
{ 
    T *m_ptr;
public:
    typedef Ret (T::*TFunction)(T1);
protected:
    TFunction m_function;

    N1Delegate(const N1Delegate &d) { };
public: 

    N1Delegate(T* ptr, TFunction function) 
        : m_ptr(ptr), m_function(function) 
    { };

    virtual Ret invoke(T1 p1)
    {
        return (m_ptr->*m_function)(p1);
    };
};

template<class T, typename Ret> 
class N1Delegate<T, Ret, void, void> : public N1DelegatePtr<Ret,void,void>
{ 
    T *m_ptr;
public:
    typedef Ret (T::*TFunction)();
protected:
    TFunction m_function;

    N1Delegate(const N1Delegate &d) { };
public: 

    N1Delegate(T* ptr, TFunction function) 
        : m_ptr(ptr), m_function(function) 
    { };

    virtual Ret invoke()
    {
        return (m_ptr->*m_function)();
    };
};

template<class T>
class N1Delegate<T, void, void, void> : public N1DelegatePtr<void,void,void>
{ 
    T *m_ptr;
public:
    typedef void (T::*TFunction)();
protected:
    TFunction m_function;

    N1Delegate(const N1Delegate &d) { };
public: 

    N1Delegate(T* ptr, TFunction function) 
        : m_ptr(ptr), m_function(function) 
    { };

    virtual void invoke()
    {
        (m_ptr->*m_function)();
    };
};


#endif //N1DELEGATE_H_2006_11_19
